package cn.backpackerxl.easyJDBC.mrss;

import cn.backpackerxl.easyJDBC.exception.NoSqlException;
import cn.backpackerxl.easyJDBC.main.EditTableImpl;
import cn.backpackerxl.easyJDBC.main.Executor;
import cn.backpackerxl.easyJDBC.main.IExecutorSelect;
import cn.backpackerxl.easyJDBC.util.*;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import static cn.backpackerxl.easyJDBC.util.Logger.logger;


/**
 * 数据库查询操作
 *
 * @author: backpackerxl
 * @create: 2021/12/23
 * @filename: EasyJDBCFind
 **/
public class EasyJDBCSelect<E> {

    /**
     * 根据id查询数据
     *
     * @param id 主键值
     * @return 数据对象
     */
    public E findById(Long id, E entity) {
        TableBean bean = BeanUtil.getBean(entity);
        String sql = String.format("%s * %s %s %s %s=?", MySQL.SELECT, MySQL.FROM, bean.getTableName(), MySQL.WHERE, bean.getKey());
        logger(entity, JDBC.SELECT, sql);
        return Executor.doExecutorSQLSelect(sql, ps -> ps.setLong(1, id), new IExecutorSelect() {
            @Override
            public E doExe(ResultSet rs) throws SQLException {
                E e = null;
                if (rs.next()) {
                    e = getEntity(entity, rs);
                }
                return e;
            }
        });
    }

    /**
     * 查询表中所有数据
     *
     * @return 数据列表
     */
    public List<E> findAll(E entity) {
        String sql = String.format("%s * %s %s", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName());
        logger(entity, JDBC.SELECT, sql);
        List<E> entityList = new ArrayList<>();
        return getResults(entity, entityList, sql);
    }

    /**
     * 获取字段值
     *
     * @param entity 实体对象
     * @param rs     结果集
     * @return 实体对象
     */
    protected E getEntity(E entity, ResultSet rs) {
        return (E) getObject(entity, rs);
    }

    /**
     * 登录操作
     *
     * @param one       一个检查字段
     * @param other     另一个检查字段
     * @param fieldName 对应的数据库字段
     * @param entity    实体
     * @return 数据对象
     */
    public E findByOneAndOther(String one, String other, E entity, String... fieldName) {
        String sql = String.format("%s * %s %s %s %s=? %s %s=?", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.WHERE, fieldName[0], MySQL.AND, fieldName[1]);
        logger(entity, JDBC.SELECT, sql);
        EditTableImpl.doWithAlterTableIndex(entity.getClass(), fieldName);
        return Executor.doExecutorSQLSelect(sql, ps -> {
            ps.setNString(1, one);
            ps.setNString(2, other);
        }, new IExecutorSelect() {
            @Override
            public E doExe(ResultSet rs) throws SQLException {
                E e = null;
                if (rs.next()) {
                    e = getEntity(entity, rs);
                }
                return e;
            }
        });
    }

    /**
     * 主要用于注册操作， 判断不可重复的字段
     *
     * @param one       一个检查字段
     * @param other     另一个检查字段
     * @param fieldName 对应的数据库字段
     * @param entity    实体
     * @return 满足条件的列表
     */
    public List<E> findByOneOrOther(String one, String other, E entity, String... fieldName) {
        List<E> entityList = new ArrayList<>();
        String sql = String.format("%s * %s %s %s %s=? %s %s=?", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.WHERE, fieldName[0], MySQL.OR, fieldName[1]);
        logger(entity, JDBC.SELECT, sql);
        EditTableImpl.doWithAlterTableIndex(entity.getClass(), fieldName);
        Executor.doExecutorSQLUtil(sql, ps -> {
            ps.setNString(1, one);
            ps.setNString(2, other);
        }, rs -> {
            while (rs.next()) {
                entityList.add(getEntity(BeanUtil.copyBean(entity), rs));
            }
        });
        return entityList;
    }

    /**
     * 通过不同的条件进行查询
     *
     * @param one       查询条件
     * @param filedName 查询字段
     * @param entity    实体
     * @return 查询结果
     */
    public List<E> findByOne(String one, String filedName, E entity) {
        List<E> entityList = new ArrayList<>();
        String sql = String.format("%s * %s %s %s %s=?", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.WHERE, filedName);
        logger(entity, JDBC.SELECT, sql);
        EditTableImpl.doWithAlterTableIndex(entity.getClass(), filedName);
        Executor.doExecutorSQLUtil(sql, ps -> ps.setNString(1, one), rs -> {
            while (rs.next()) {
                entityList.add(getEntity(BeanUtil.copyBean(entity), rs));
            }
        });
        return entityList;
    }

    /**
     * 分页查询
     *
     * @param pageSize    每页显示数据量
     * @param currentPage 当前页数
     * @param entity      实体
     * @return 分页对象
     */
    public PageBean<E> pageEntityAll(int pageSize, int currentPage, E entity) {
        PageBean<E> pageBean = new PageBean<>();
        int totalSize = findAll(entity).size();
        pageBean.setTotalObj(totalSize);
        pageBean.setCurrentPage(currentPage);
        pageBean.setPageSize(pageSize);
        if (totalSize % pageSize == 0) {
            pageBean.setTotalPage(totalSize / pageSize);
        } else {
            pageBean.setTotalPage(totalSize / pageSize + 1);
        }
        List<E> temp = new ArrayList<>();
        String sql = String.format("%s * %s %s %s ?,?", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.LIMIT);
        return getPageBean(pageSize, currentPage, entity, pageBean, temp, sql);
    }


    /**
     * 模糊搜索
     *
     * @param key       关键词
     * @param filedName 查询字段
     * @param entity    实体
     * @return 搜索结果
     */
    public List<E> search(String key, String filedName, E entity) {
        List<E> entityList = new ArrayList<>();
        String sql = String.format("%s * %s %s %s %s %s %s%s%s", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.WHERE, filedName, MySQL.LIKE, "'%", key, "%'");
        logger(entity, JDBC.SELECT, sql);
        EditTableImpl.doWithAlterTableIndex(entity.getClass(), filedName);
        return getResults(entity, entityList, sql);
    }

    private List<E> getResults(E entity, List<E> entityList, String sql) {
        Executor.doExecutorSQLUtil(sql, rs -> {
            while (rs.next()) {
                entityList.add(getEntity(BeanUtil.copyBean(entity), rs));
            }
        });
        return entityList;
    }

    /**
     * 分页搜索
     *
     * @param key         关键词
     * @param filedName   查询字段
     * @param pageSize    每页显示数据量
     * @param currentPage 当前页数
     * @param entity      实体
     * @return 分页搜索结果
     */
    public PageBean<E> search(String key, String filedName, int pageSize, int currentPage, E entity) {
        PageBean<E> pageBean = new PageBean<>();
        int totalSize = search(key, filedName, entity).size();
        pageBean.setTotalObj(totalSize);
        pageBean.setCurrentPage(currentPage);
        pageBean.setPageSize(pageSize);
        if (totalSize % pageSize == 0) {
            pageBean.setTotalPage(totalSize / pageSize);
        } else {
            pageBean.setTotalPage(totalSize / pageSize + 1);
        }
        List<E> temp = new ArrayList<>();
        String sql = String.format("%s * %s %s %s %s %s %s%s%s %s ?,?", MySQL.SELECT, MySQL.FROM, BeanUtil.getBean(entity).getTableName(), MySQL.WHERE, filedName, MySQL.LIKE, "'%", key, "%'", MySQL.LIMIT);
        EditTableImpl.doWithAlterTableIndex(entity.getClass(), filedName);
        return getPageBean(pageSize, currentPage, entity, pageBean, temp, sql);
    }

    private PageBean<E> getPageBean(int pageSize, int currentPage, E entity, PageBean<E> pageBean, List<E> temp, String sql) {
        logger(entity, JDBC.SELECT, sql);
        Executor.doExecutorSQLUtil(sql, ps -> {
            ps.setInt(1, (currentPage - 1) * pageSize);
            ps.setInt(2, pageSize);
        }, rs -> {
            while (rs.next()) {
                temp.add(getEntity(BeanUtil.copyBean(entity), rs));
            }
        });
        pageBean.setPageList(temp);
        return pageBean;
    }

    /**
     * 连接查询
     *
     * @param sql    sql语句
     * @param target 查询目标的实体对象
     * @return 连接查询结果
     */
    public <T> List<T> findByJoin(String sql, T target) {
        logger(target, JDBC.SELECT, sql);
        List<T> joinEntity = new ArrayList<>();
        if (sql.length() != 0) {
            Executor.doExecutorSQLUtil(sql, rs -> {
                while (rs.next()) {
                    joinEntity.add((T) getObjectEntity(BeanUtil.copyBean(target), rs));
                }
            });
        } else {
            throw new NoSqlException("the method is not a BasicQuery commend");
        }
        return joinEntity;
    }

    /**
     * 获取字段的值
     *
     * @param entity 实体对象
     * @param rs
     * @return Object对象
     * @throws Exception
     */
    protected Object getObjectEntity(Object entity, ResultSet rs) {
        return getObject(entity, rs);
    }

    private Object getObject(Object entity, ResultSet rs) {
        Class<?> clazz = entity.getClass();
        ReflectUtil.doWithLocalSQLFields(clazz, field -> SqlFactory.buildField(entity, rs, field));
        return entity;
    }

    /**
     * 连接查询
     *
     * @param sql    sql语句
     * @param target 查询目标的实体对象
     * @param args   参数数组
     * @return 连接查询结果
     */
    public <T> List<T> findByJoin(String sql, T target, Object... args) {
        logger(target, JDBC.SELECT, sql);
        List<T> joinEntity = new ArrayList<>();
        if (sql.length() != 0) {
            Executor.doExecutorSQLUtil(sql, ps -> {
                int i = 1;
                for (Object o : args) {
                    ps.setObject(i, o);
                    i++;
                }
            }, rs -> {
                while (rs.next()) {
                    joinEntity.add((T) getObjectEntity(BeanUtil.copyBean(target), rs));
                }
            });
        } else {
            throw new NoSqlException("the method is not a BasicQuery commend.");
        }
        return joinEntity;
    }

    /**
     * 自定义查询
     *
     * @param sql    sql语句
     * @param entity 实体对象
     * @param args   参数数组
     * @return 对应的数据类型
     */
    public List<E> findByQuery(String sql, E entity, Object... args) {
        logger(entity, JDBC.SELECT, sql);
        List<E> queryEntity = new ArrayList<>();
        if (sql.length() != 0) {
            Executor.doExecutorSQLUtil(sql, ps -> {
                int i = 1;
                for (Object o : args) {
                    ps.setObject(i, o);
                    i++;
                }
            }, rs -> {
                while (rs.next()) {
                    queryEntity.add(getEntity(BeanUtil.copyBean(entity), rs));
                }
            });
        } else {
            throw new NoSqlException("the method is not a BasicQuery commend.");
        }
        return queryEntity;
    }
}
